package com.edu.course.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.edu.api.entity.common.Code;
import com.edu.api.entity.common.JwtUtil;
import com.edu.api.entity.common.ResponseDTO;
import com.edu.api.entity.course.Course;
import com.edu.api.entity.coursedto.CourseAndMediaDto;
import com.edu.api.entity.coursedto.CourseDto;
import com.edu.course.service.CourseDtoRepository;
import com.edu.course.service.OrderFeign;
import com.edu.course.service.CourseService;
import com.edu.course.mapper.CourseMapper;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
    implements CourseService{

    @Autowired
    CourseMapper courseMapper;

    @Autowired
    CourseService courseService;

    @Autowired
    OrderFeign orderFeign;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    public CourseDtoRepository courseRepository;

    @Autowired
    public ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public ResponseDTO updateSales(String courseId) {
        UpdateWrapper<Course> updateWrapper = new UpdateWrapper();
        updateWrapper.eq("id",courseId);
        updateWrapper.setSql("sales = sales+1");
        courseService.update(updateWrapper);
        return new ResponseDTO(Code.GET_OK,"成功",null);
    }

    @Override
    public synchronized ResponseDTO getAllCourse(Map map, HttpServletRequest request) {
        if (!JwtUtil.checkToken(request)){//未登录
//            if (redisTemplate.opsForValue().get("AllCourse") == null) {
                List<CourseDto> allCourse = courseMapper.getAllCourse();
                courseRepository.deleteAll();
                courseRepository.saveAll(allCourse);
                redisTemplate.opsForValue().set("AllCourse",allCourse);
//            }
            //es查询
            AggregatedPage coursePage = esQuery(map);
            if (coursePage==null){
                return new ResponseDTO(Code.GET_OK,"成功",null);
            }
            return new ResponseDTO(Code.GET_OK,"成功",coursePage.getContent());
        }
        List<Long> content = (List<Long>) orderFeign.getCourseIds(JwtUtil.getMemberIdByJwtToken(request)).getContent();
        courseRepository.deleteAll();

        if(content.isEmpty()) {
            courseRepository.saveAll(courseMapper.getAllCourse());
            AggregatedPage coursePage = esQuery(map);
            if (coursePage==null){
                return new ResponseDTO(Code.GET_OK,"成功",null);
            }
            return new ResponseDTO(Code.GET_OK, "成功", coursePage.getContent());
        }
        courseRepository.saveAll(courseMapper.getNoBuyCourse(content));
        AggregatedPage coursePage = esQuery(map);
        if (coursePage==null){
            return new ResponseDTO(Code.GET_OK,"成功",null);
        }
        return new ResponseDTO(Code.GET_OK,"成功",coursePage.getContent());
    }

    @Override
    public ResponseDTO getMyCoursesById(HttpServletRequest request) {
        List<Long> content = (List<Long>) orderFeign.getCourseIds(JwtUtil.getMemberIdByJwtToken(request)).getContent();
        if (content.isEmpty())
            return new ResponseDTO(Code.GET_OK,"成功",null);
        List<CourseDto> buyCourse = courseMapper.getBuyCourse(content);
        return new ResponseDTO(Code.GET_OK,"成功",buyCourse);
    }

    @Override
    public ResponseDTO getCourseDetails(String courseId) {
        List<CourseAndMediaDto> courseAndMediaByCourseId = courseMapper.getCourseAndMediaByCourseId(courseId);
        return new ResponseDTO(Code.GET_OK,"成功",courseAndMediaByCourseId);
    }

    public AggregatedPage setHighlight(SearchQuery query,Class aclass){
        return elasticsearchTemplate.queryForPage(query, CourseDto.class, new SearchResultMapper() {

            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                // 获取高亮搜索数据
                List<CourseDto> list = new ArrayList<>();
                SearchHits hits = searchResponse.getHits();
                if (hits == null || hits.getHits().length <= 0) {
                    return null;
                }
                CourseDto esProduct = null;
                for (SearchHit searchHit : hits) {
                    //将map数据，转为对象数据
                    Map<String, Object> tempMap = searchHit.getSourceAsMap();
//                        esProduct = JSONUtil.toBean(JSONUtil.parseFromMap(tempMap),CourseDto.class);
                    esProduct = JSON.parseObject(JSON.toJSONString(tempMap), CourseDto.class);
                    //获取高亮数据
                    //重新设置高亮数据name
                    HighlightField highlightName = searchHit.getHighlightFields().get("courseName");
                    //必须判断是否为空，可能根据name中没有高亮数据，所以在高亮集合中是没有该数据的
                    if (highlightName != null && highlightName.getFragments().length > 0)
                        esProduct.setCourseName(highlightName.getFragments()[0].toString());
                    //重新设置高亮数据标题
                    HighlightField highlightSubTitle = searchHit.getHighlightFields().get("teacher.teacherName");
                    //必须判断是否为空
                    if (highlightSubTitle != null && highlightSubTitle.getFragments().length > 0)
                        esProduct.getTeacher().setTeacherName(highlightSubTitle.getFragments()[0].toString());
                    list.add(esProduct);
                }
                if (list.size() > 0) {
                    return new AggregatedPageImpl<T>((List<T>) list, pageable,
                            searchResponse.getHits().getTotalHits());
                }
                return null;
            }
        });
    }

    public AggregatedPage esQuery(Map map){
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (map.get("courseName") != null && !map.get("courseName").equals("")){
            boolQueryBuilder.must(QueryBuilders.matchQuery("courseName",map.get("courseName")));
        }
        if (map.get("teacherName")!=null && !map.get("teacherName").equals("")){
            boolQueryBuilder.must(QueryBuilders.matchQuery("teacher.teacherName",map.get("teacherName")));
        }
        if (map.get("minMoney")!=null && !map.get("minMoney").equals("")){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("discounts").gte(map.get("minMoney")))
                    .should(QueryBuilders.rangeQuery("price").gte(map.get("minMoney")));
        }
        if (map.get("maxMoney")!=null && !map.get("maxMoney").equals("")){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("discounts").lte(map.get("maxMoney")))
                    .should(QueryBuilders.rangeQuery("price").lte(map.get("maxMoney")));
        }
        //添加高亮
        List<String> highlightFields = new ArrayList<>();
        highlightFields.add("courseName");
        highlightFields.add("teacher.teacherName");
        String preTag = "<font color='red'>";//获取其他值#fc1944
        String postTag = "</font>";
        HighlightBuilder.Field[] fields = new HighlightBuilder.Field[highlightFields.size()];
        for (int x = 0; x < highlightFields.size(); x++) {
            //设置高亮显示的数据的前缀标签和后缀标签
            fields[x] = new HighlightBuilder.Field(highlightFields.get(x)).preTags(preTag)
                    .postTags(postTag);
        }

        queryBuilder.withHighlightFields(fields);

        queryBuilder.withSort(new ScoreSortBuilder())
//                .withSort(SortBuilders.fieldSort("sales").order(SortOrder.DESC));
                .withSort(new FieldSortBuilder("sales").order(SortOrder.DESC));
        NativeSearchQuery query  = queryBuilder.withQuery(boolQueryBuilder).build();
        //高亮
        AggregatedPage<CourseDto> coursePage = setHighlight(query,CourseDto.class);
        return coursePage;
    }

}




